package express.compiler;

import express.bttree.Utils;
import org.apache.commons.lang3.StringUtils;

import java.awt.event.KeyEvent;
import java.util.List;


/**
 * 语法分析
 * --------------------------------
 * Or      ->    And OrTail
 * OrTail  ->    + And OrTail
 *           |     - And OrTail
 *           |     null
 *
 * And      ->    BracketOrItems AndTail
 * AndTail  ->    * BracketOrItems AndTail
 *           |     / BracketOrItems AndTail
 *           |     null
 *
 * bracketOrItems    ->    (Or)
 *           |              Items
 */
public class Parser {
    private List<String> tokens;
    private String currToken = "";
    private int currIndex = -1;


    private boolean isAnd() {
        return StringUtils.equalsAnyIgnoreCase(this.currToken,"and","&&","&","*","/");
    }

    private boolean isOr() {
        return StringUtils.equalsAnyIgnoreCase(this.currToken,"or","||","|","+","-");
    }

    private boolean isOp() {
        return Utils.isOp(this.currToken);
    }

    private boolean isStartBracket() {
        boolean ok =  StringUtils.equals(this.currToken,"(");
        return ok;
    }

    private boolean isEndBracket() {
        boolean ok = StringUtils.equals(this.currToken,")");
        return ok;
    }

    private boolean isStartParam() {
        boolean ok =  StringUtils.equals(this.currToken, Keywords.PARAM_START);
        return ok;
    }

    private boolean isEndParam() {
        boolean ok = StringUtils.equals(this.currToken, Keywords.PARAM_END);
        return ok;
    }


    private boolean isItem() {
        return !StringUtils.equalsAnyIgnoreCase(this.currToken,"and","or","(",")","&","&&","|","||","+","-","*","/","", Keywords.PARAM_START, Keywords.PARAM_END);
    }

    private boolean isEnd() {
        return this.currIndex >= this.tokens.size();
    }

    private void printLog(String log) {
         //System.out.println("处理：" + log);
    }

    public void moveNext() {
        if(currIndex >= this.tokens.size()) {
            throw new RuntimeException("move next error");
        }

        if(currIndex >= this.tokens.size() - 1) {
            this.currIndex++;
            this.currToken = "";
            return;
        }
        currIndex++;
        this.currToken = this.tokens.get(currIndex);
    }

    private RuntimeException newException() {
        return new RuntimeException("不处理该关键字，token:" + this.currToken);
    }

    public Parser(List<String> tokens) {
        this.tokens = tokens;
    }

    public SyntaxNode parse() {
        SyntaxNode root = new SyntaxNode(SyntaxNodeType.Nodes);
        moveNext();
        if(or(root) && isEnd()) {
            return root;
        } else {
            return null;
        }
    }

    private boolean or(SyntaxNode parent) {
        SyntaxNode andExpr = new SyntaxNode(SyntaxNodeType.Nodes);
        parent.addChild(andExpr);
        if(!and(andExpr)) {
            return false;
        } else {
            return orTail(parent);
        }
    }

    private boolean orTail(SyntaxNode parent) {
        if(this.isOr()) {
            SyntaxNode opNode = new SyntaxNode(SyntaxNodeType.Or);
            opNode.setValue(this.currToken);
            parent.addChild(opNode);

            printLog(this.currToken);
            moveNext();

            SyntaxNode andNode = new SyntaxNode(SyntaxNodeType.Nodes);
            parent.addChild(andNode);

            if(!and(andNode)) {
                return false;
            } else {
                return orTail(parent);
            }
        } else {
            return true;
        }
    }

    private boolean and(SyntaxNode parent) {
        if(!bracketOrItems(parent)) {
            return false;
        } else {
            return andTail(parent);
        }
    }

    private boolean andTail(SyntaxNode parent) {
        if(this.isAnd()) {
            SyntaxNode opNode = new SyntaxNode(SyntaxNodeType.And);
            opNode.setValue(this.currToken);
            parent.addChild(opNode);

            printLog(this.currToken);
            moveNext();

            if(!bracketOrItems(parent)) {
                return false;
            } else {
                return andTail(parent);
            }
        } else {
           return true;
        }
    }

    private boolean bracketOrItems(SyntaxNode parent) {
        if(this.isStartBracket()) {
            this.moveNext();
            this.printLog("(");
            SyntaxNode bracketNode = new SyntaxNode(SyntaxNodeType.Nodes);
            parent.addChild(bracketNode);
            if(!or(bracketNode)) {
                return false;
            } else {
                if(!this.isEndBracket()) {
                    throw newException();
                }
                this.moveNext();
                this.printLog(")");
                return true;
            }
        } else if(this.isItem()) {
            SyntaxNode exprNode = new SyntaxNode(SyntaxNodeType.Expr);
            parent.addChild(exprNode);
            if(!item(exprNode)) {
                return false;
            } else {
                return itemTail(exprNode);
            }
        } else {
            throw newException();
        }
    }

    private boolean item(SyntaxNode parent) {
        printLog("item:" + this.currToken);
        SyntaxNode itemNode = new SyntaxNode(SyntaxNodeType.Item, this.currToken);
        parent.addChild(itemNode);
        this.moveNext();
        return true;
    }

    private boolean itemTail(SyntaxNode expr) {
        if(this.isItem()) {
            if(!item(expr)) {
                return false;
            } else {
                return itemTail(expr);
            }
        } else if(this.isStartParam()){
            //参数列表之前只能有一个项目
            if(expr.getChildNodes().size() != 1) {
                throw newException();
            }
            if(!paramList(expr)) {
                return false;
            } else {
                //参数列表结束后，如果接下来不符合这些规则，则表达式不合法
                if(!this.isEnd() && !this.isOp() && !this.isAnd() && !this.isOr()) {
                    throw newException();
                }
                return itemTail(expr);
            }
        } else {
            return true;
        }
    }


    private boolean paramList(SyntaxNode parent) {
        if(this.isStartParam()) {
            printLog(Keywords.PARAM_START);
            moveNext();
            //直接闭合
            if(this.isEndParam()) {
                printLog(Keywords.PARAM_END);
                moveNext();
                return true;
            }

            if(!item(parent)) {
                return false;
            } else {
                return paramListTail(parent);
            }
        } else {
            throw newException();
        }
    }

    private boolean paramListTail(SyntaxNode parent) {
        if(isItem()) {
            if(!item(parent)) {
                return false;
            } else {
                return paramListTail(parent);
            }
        } else if(this.isEndParam()) {
            printLog(Keywords.PARAM_END);
            moveNext();
            return true;
        } else {
            throw newException();
        }
    }
}
